"""
不同的运算符
算术运算符:  +,-,*,/,//,%,**
赋值运算符:  =,+=,-=,*=,/=,//=,%=
位运算:     &,~,<<,>>,^
关系运算符:  ==,!=,>,<,>=,<=
逻辑运算符:  and,or,not
成员运算符:  in,not in
身份运算符:  is

表达式: 由变量，常量，运算符组成的式子称为表达式
"""

"""
算术运算符
+:  加
-:  减
*:  乘
/:  除
//: 取整除
%:  取模(python中是取模，java中是取余数，区别在于负数运算，取余数是结果符号与被除数相同，取模是与除数相同)
**: 幂

算术运算符的优先级-由高到低
注:正常使用两个运算符要加()，不加只有在考试中考查运算符优先级才会出现
**
* / % //
+ -
"""
print(4 * "*", '算术运算符', 4 * "*")
num_10 = 10
num_3 = 3
print(num_10 + num_3)
print(num_10 - 1)
print(num_10 * num_3)
print(num_10 / num_3)
print(num_10 // num_3)
print(10 % -4)
print(-10 % 4)
print(num_10 ** 2)
print(1 + 2 * 3 ** 2)

"""
赋值运算符
=:     简单的赋值运算符
+=:    加法赋值运算符
-+:    减法赋值运算符
*=:    乘法赋值运算符
/=:    除法赋值运算符
//=:   取整除赋值运算符
%=:    取模赋值运算符
**=:   幂赋值运算符 eg: c **=a 等效于 c = c**a
"""
print("*" * 4, "赋值运算符", "*" * 4)
num_y = 6
num_x = 2
num_x += num_y
print(num_x)
num_x -= num_y
print(num_x)
num_y //= num_x
print(num_y)
num_y %= num_x
print(num_y)

"""
比较(关系)运算符
注: 操作数是运算符作用的对象，在高级语言中可以是变量，常量或表达式
==:     检查两个操作数的值是否相同
!=:     检查两个操作数的值是否不同
>:      检查左操作数的值是否大于右操作数的值
<:      检查左操作数的值是否小于右操作数的值
>=:     检查左操作数的值是否大于或等于右操作数的值
<=:     检查左操作数的值是否小于或等于右操作数的值
"""
print("*" * 4, "比较运算符", "*" * 4)
print(3 == 3)
print(3 != 3)
print(3 > 2)
print(3 < 2)
print(3 >= 3)
print(3.0 >= 3)  # 可以对浮点型进行比较
print(True > False)  # 可以对布尔类型进行比较
print("hi" > "hello")  # 可以对字符串进行比较，对每个字符的ascii码值进行比较
print(ord("h"))  # 可以通过ord()函数获取字符的ASCII码值

"""
逻辑运算符
and:  与
or:   或
not:  非

逻辑运算符优先级 not>and>or
短路运算是指逻辑运算符（and 和 or）在计算表达式时，如果已经能确定最终结果，就不再计算剩余部分，从而提高效率。Python、C/C++、Java、JavaScript 等语言均支持短路运算。
注:正常使用两个运算符要加()，不加只有在考试中考查运算符优先级才会出现
"""
print("*" * 4, "逻辑运算符", "*" * 4)
print(True and False)
print(True or False and False)
print(not True)
print(1 == 1 and 2 > 3)
print('hello' and 'a')
print('hello' or 'a')  # 短路运算，由于hello是True且是或的逻辑,因此不用判断后面的部分
print(not '')
print("hello" or "a" and not '')
print("hello" and "a" and '')

"""
位运算符
&: 按位与-参与运算的两个二进制数，对应位均为1则为1，否则为0
|: 按位或-参与运算的两个二进制数，对应位有一个为1则为1，否则为0
^: 按位异或-参与运算的两个二进制数，对应位不同则为1，否则位0
~: 按位取反-对二进制数进行取反操作，0变1,1变0
<<: 左移动-二进制数全部向左移动，高位丢弃，低位补0
>>: 右移动-二进制数全部向右移动，低位丢弃，高位补0
"""
print("*" * 4, "位运算符", "*" * 4)
# 按位与&
'''
010
110
---
010
'''
print(4 & 12)

# 按位或|
'''
101
110
---
111
'''
print(5 | 6)

# 按位异或^
'''
0111
1001
----
1110
'''
print(7 ^ 9)

# 按位取反~
# 正数取反: 正数的补码是其原码，取反后得到的是该负数补码的反码
# 负数取反: 负数的补码取反后得到的是其绝对值的原码减1
'''
正数取反
~5
正数补码为其原码
0000 0101
取反(包括符号位)得到负数的补码形式
1111 1010
补码减一变为反码
1111 1001
反码转为原码(符号位不变)
1000 0110
-6
公式~(x)=-(x+1)

负数取反
~-2
负数其绝对值的原码
0000 0010
负数原码
1000 0010
反码(除符号位取反)
1111 1101
反码加一(补码)
1111 1110
按位取反
0000 0001
公式~(x)=-(x+1)
'''
print(~5)
print(~-2)

# 左移<< 右移>>
'''
5 << 2
0000 0101
0001 0100
x<<n = x 乘 2的n次幂

-3 >> 2
1000 0011
1000 0001
x>>n - 向下取整(x除以 2的n次幂)
'''
print(5 << 2)
print(-3 >> 2)

"""
成员运算符
in: 如果在指定序列中找到返回True，否则返回False
not in: 如果在指定序列中没有找到返回True，否则返回False
"""

print(3 in (3, 4))
print("hi" not in "hello")

"""
身份运算符
is: 判断两个标识符是否引用同一个对象，是返回True，否则返回False
is not: 判断两个标识符是否不是引用同一个对象，是返回True，否则返回False
"""
a = 1
b = 1
print(a is b)
print(a is not b)

"""
运算符的优先级
由高到低
()                     括号(分组)
**                     幂
~x +x -x               按位取反、一元运算符(正负号)
* / % //               乘、除、取模、取整除
+ -                    加法、减法
<< >>                  左移、右移
&                      按位与
^                      按位异或
|                      按位或
== != > < >= <=        比较运算
is,is not,in,not in    身份、成员运算
not                    逻辑非
and                    逻辑与
or                     逻辑或
= += -= /= %= //= **=  赋值运算符
"""

"""
在 Python 或 Java 中运行 0.1 + 0.2，结果并不是 0.3，而是
0.30000000000000004
这是因为 浮点数的存储方式 导致的，根本原因在于 IEEE 754 浮点数标准 和 二进制无法精确表示某些十进制小数。
"""
print(0.1 + 0.2)
